<?php

namespace app\common\command\Sync;

use app\common\model\DingtalkAttendance;
use app\common\model\DingtalkDepartment;
use app\common\model\DingtalkUser;
use app\common\model\DingtalkUserDepartment;
use ChenDingtalk\DingtalkManager;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;

class Dingtalk extends Command
{
    /**
     * @var DingtalkManager
     */
    protected $dingtalk;

    protected function configure()
    {
        $this->setName('sync:dingtalk')->setDescription('Sync dingtalk data');
    }

    /**
     * @param Input $input
     * @param Output $output
     * @return int|void|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function execute(Input $input, Output $output)
    {
        $this->dingtalk = new DingtalkManager(config('dingtalk'));

        //同步部门信息
        $this->syncDepartment();

        //同步用户信息
        $this->syncUser();

        //同步用户考勤信息
        $this->syncAttendance();
    }

    /**
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function syncDepartment()
    {
        //获取企业在钉钉中的所有部门
        $response = $this->dingtalk->department()->lists();
        $departments = $response->department;

        //同步部门信息
        $dingtalkDepartmentModel = new DingtalkDepartment();
        foreach ($departments as $department) {
            $dingtalkDepartmentModel->updateOrCreate(['id' => $department->id], [
                'title' => $department->name,
                'parent_id' => $department->parentid ?? 0
            ]);
        }
    }

    /**
     * @throws \think\exception\DbException
     */
    protected function syncUser()
    {
        $departments = DingtalkDepartment::all();
        //获取部门下所有用户ID
        $users = [];
        $userids = [];
        foreach ($departments as $department) {
            $response = $this->dingtalk->user()->getDeptMember($department->id);
            $userids = array_merge($userids, $response->userIds);
        }
        foreach ($userids as $userid) {
            $response = $this->dingtalk->user()->get($userid);
            $users[] = $response;
        }

        $dingtalkUserModel = new DingtalkUser();
        $dingtalkUserDepartmentModel = new DingtalkUserDepartment();

        //同步用户数据
        foreach ($users as $user) {
            $dingtalkUserModel->updateOrCreate(['id' => $user->userid], [
                'unionid' => $user->unionid,
                'openid' => $user->openId,
                'name' => $user->name,
                'email' => $user->email ?? null,
                'mobile' => $user->mobile,
                'department' => json_encode($user->department ?? []),
                'roles' => json_encode($user->roles ?? []),
                'order_in_depts' => $user->orderInDepts,
                'is_leader_in_depts' => $user->isLeaderInDepts,
                'is_hide' => $user->isHide,
                'is_admin' => $user->isAdmin,
                'is_senior' => $user->isSenior,
                'is_boss' => $user->isBoss,
            ]);
            $dingtalkUserDepartmentModel->where('user_id', $user->userid)->delete();
            $user_departments = [];
            foreach ($user->department ?? [] as $department_id) {
                $user_departments[] = ['user_id' => $user->userid, 'department_id' => $department_id];
            }
            $dingtalkUserDepartmentModel->insertAll($user_departments);
        }
    }

    /**
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function syncAttendance()
    {
        $attendances = [];

        $offset = 0;
        $size = 2;

        $workDateTo = strtotime(date('Y-m-d'));
        $workDateFrom = $workDateTo - 86400 * 7;
        $dingtalkUserModel = new DingtalkUser();
        while (true) {
            $users = $dingtalkUserModel->limit($offset,$size)->select();
            if (empty($users)) break;
            $userIdList = collect($users)->column('id');

            $dingtalkOffset = 0;
            $dingtalkSize = 20;
            $dingtalkFrom = date('Y-m-d H:i:s', $workDateFrom);
            $dingtalkTo = date('Y-m-d H:i:s', $workDateTo);
            while (true) {
                $response = $this->dingtalk->attendance()
                    ->lists($dingtalkFrom, $dingtalkTo, $userIdList, $dingtalkOffset, $dingtalkSize);
                $attendances = array_merge($attendances, $response->recordresult);
                if (!$response->hasMore) break;
                $dingtalkOffset += $dingtalkSize;
            }

            $offset += $size;
        }

        $dingtalkAttendanceModel = new DingtalkAttendance();

        foreach ($attendances as $attendance) {
            $dingtalkAttendanceModel->updateOrCreate(['id' => $attendance->id], [
                'user_id' => $attendance->userId,
                'corp_id' => $attendance->corpId,
                'plan_id' => $attendance->planId,
                'record_id' => $attendance->recordId ?? null,
                'group_id' => $attendance->groupId,
                'proc_inst_id' => $attendance->procInstId ?? null,
                'approve_id' => $attendance->approveId ?? null,
                'source_type' => $attendance->sourceType,
                'check_type' => $attendance->checkType,
                'location_result' => $attendance->locationResult,
                'time_result' => $attendance->timeResult,
                'base_check_time' => date('Y-m-d H:i:s', $attendance->baseCheckTime / 1000),
                'user_check_time' => date('Y-m-d H:i:s', $attendance->userCheckTime / 1000),
                'work_date' => date('Y-m-d H:i:s', $attendance->workDate / 1000),
            ]);
        }

    }
}